package main

import (
	"crypto/subtle"
	"flag"
	"fmt"
	"log"
	"net/http"
	"path/filepath"

	"golang.org/x/net/webdav"
)

type Config struct {
	Host     string
	Port     string
	RootDir  string
	Username string
	Password string
	EnableTLS bool
	CertFile  string
	KeyFile   string
}

type WebDAVServer struct {
	config *Config
	handler *webdav.Handler
}

func NewWebDAVServer(cfg *Config) *WebDAVServer {
	absPath, err := filepath.Abs(cfg.RootDir)
	if err != nil {
		log.Fatal("获取绝对路径失败:", err)
	}

	fmt.Printf("WebDAV 根目录: %s\n", absPath)

	return &WebDAVServer{
		config: cfg,
		handler: &webdav.Handler{
			FileSystem: webdav.Dir(cfg.RootDir),
			LockSystem: webdav.NewMemLS(),
			Logger: func(r *http.Request, err error) {
				if err != nil {
					log.Printf("WEBDAV [%s] %s %s - ERROR: %v",
						   r.RemoteAddr, r.Method, r.URL.Path, err)
				} else {
					log.Printf("WEBDAV [%s] %s %s",
						   r.RemoteAddr, r.Method, r.URL.Path)
				}
			},
		},
	}
}

func (s *WebDAVServer) basicAuth(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// 如果未设置用户名密码，则跳过认证
		if s.config.Username == "" && s.config.Password == "" {
			handler.ServeHTTP(w, r)
			return
		}

		username, password, ok := r.BasicAuth()
		if !ok {
			s.requireAuth(w)
			return
		}

		// 使用恒定时间比较防止时序攻击
		if subtle.ConstantTimeCompare([]byte(username), []byte(s.config.Username)) != 1 ||
			subtle.ConstantTimeCompare([]byte(password), []byte(s.config.Password)) != 1 {
				s.requireAuth(w)
				return
			}

			handler.ServeHTTP(w, r)
	})
}

func (s *WebDAVServer) requireAuth(w http.ResponseWriter) {
	w.Header().Set("WWW-Authenticate", `Basic realm="WebDAV Server"`)
	http.Error(w, "需要认证", http.StatusUnauthorized)
}

func (s *WebDAVServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// 添加 CORS 头（可选）
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE, OPTIONS, PROPFIND, MKCOL, MOVE, COPY")
	w.Header().Set("Access-Control-Allow-Headers", "Authorization, Content-Type, Depth, If-Match, If-None-Match")

	// 处理 OPTIONS 请求
	if r.Method == "OPTIONS" {
		w.WriteHeader(http.StatusOK)
		return
	}

	s.handler.ServeHTTP(w, r)
}

func main() {
	cfg := Config{}

	flag.StringVar(&cfg.Host, "host", "0.0.0.0", "监听地址")
	flag.StringVar(&cfg.Port, "port", "8080", "监听端口")
	flag.StringVar(&cfg.RootDir, "root", "/tmp", "WebDAV 根目录")
	flag.StringVar(&cfg.Username, "user", "", "用户名（留空则无需认证）")
	flag.StringVar(&cfg.Password, "pass", "", "密码（留空则无需认证）")
	flag.BoolVar(&cfg.EnableTLS, "tls", false, "启用 HTTPS")
	flag.StringVar(&cfg.CertFile, "cert", "", "TLS 证书文件")
	flag.StringVar(&cfg.KeyFile, "key", "", "TLS 私钥文件")
	flag.Parse()

	server := NewWebDAVServer(&cfg)

	authHandler := server.basicAuth(server)

	addr := fmt.Sprintf("%s:%s", cfg.Host, cfg.Port)

	fmt.Printf("WebDAV 服务器启动在 %s\n", addr)
	fmt.Printf("根目录: %s\n", cfg.RootDir)
	if cfg.Username != "" {
		fmt.Printf("认证用户: %s\n", cfg.Username)
	} else {
		fmt.Println("认证: 禁用")
	}
	fmt.Println("使用 Ctrl+C 停止服务器")

	var err error
	if cfg.EnableTLS {
		if cfg.CertFile == "" || cfg.KeyFile == "" {
			log.Fatal("启用 TLS 需要提供证书和私钥文件")
		}
		err = http.ListenAndServeTLS(addr, cfg.CertFile, cfg.KeyFile, authHandler)
	} else {
		err = http.ListenAndServe(addr, authHandler)
	}

	if err != nil {
		log.Fatal("服务器启动失败:", err)
	}
}
